package com.xzxy.xmlg_backend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xzxy.xmlg_backend.entity.OperationLog;
import com.xzxy.xmlg_backend.mapper.OperationLogMapper;
import com.xzxy.xmlg_backend.service.IOperationLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

@Service
public class OperationLogServiceImpl extends ServiceImpl<OperationLogMapper, OperationLog> implements IOperationLogService, ApplicationRunner {
    
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final ZoneId CHINA_ZONE = ZoneId.of("Asia/Shanghai");
    
    @Override
    public long cleanLogRegularly(Integer days){
        LocalDateTime cutoffTime = LocalDateTime.now(CHINA_ZONE).minusDays(days);

        LambdaQueryWrapper<OperationLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.lt(OperationLog::getLastOperationTime, cutoffTime);

        long count = this.count(wrapper);
        if (count > 0) {
            this.remove(wrapper);
        }
        return count;
    }

    /**
     * 每周二凌晨1点执行深度清理任务
     * 删除1天前的所有日志记录
     */
    @Scheduled(cron = "0 0 1 ? * Tue", zone = "Asia/Shanghai")
    public void CleanUpAtTue() {
        try {
            long count = cleanLogRegularly(1);
            System.out.println("定时清理任务执行完成，清理了" + count + "条日志记录，执行时间: " + 
                LocalDateTime.now(CHINA_ZONE).format(FORMATTER));
        } catch (Exception e) {
            System.err.println("定时清理任务执行失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 系统启动时检查是否有遗漏的清理任务
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        checkAndExecuteMissedCleanup();
    }

    /**
     * 检查并执行遗漏的清理任务
     * 通过查询数据库中的日志记录来判断是否需要清理
     */
    public void checkAndExecuteMissedCleanup() {
        try {
            LocalDateTime now = LocalDateTime.now(CHINA_ZONE);
            
            // 计算应该执行清理的时间点
            LocalDateTime shouldCleanupAfter = calculateLastScheduledCleanupTime(now);
            
            System.out.println("当前时间: " + now.format(FORMATTER));
            System.out.println("应该在此时间后清理: " + shouldCleanupAfter.format(FORMATTER));
            
            // 查询是否有超过应该清理时间的日志记录
            LambdaQueryWrapper<OperationLog> checkWrapper = new LambdaQueryWrapper<>();
            checkWrapper.lt(OperationLog::getLastOperationTime, shouldCleanupAfter)
                       .orderByDesc(OperationLog::getLastOperationTime)
                       .last("LIMIT 1");
            
            OperationLog oldestLogBeforeCleanup = this.getOne(checkWrapper);
            
            if (oldestLogBeforeCleanup != null) {
                System.out.println("发现需要清理的日志，最早记录时间: " + 
                    oldestLogBeforeCleanup.getLastOperationTime().format(FORMATTER));
                
                // 执行清理任务
                long cleanedCount = cleanLogRegularly(1);
                System.out.println("启动时清理任务执行完成，清理了" + cleanedCount + "条日志记录");
            } else {
                System.out.println("系统启动检查：没有发现需要清理的过期日志");
            }
            
        } catch (Exception e) {
            System.err.println("启动时清理检查出现异常: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 计算最近应该执行清理的时间点
     * 使用中国时区进行计算
     */
    private LocalDateTime calculateLastScheduledCleanupTime(LocalDateTime now) {
        LocalDateTime result;
        
        // 获取本周二凌晨1点（中国时区）
        LocalDateTime thisWeekTuesday = now.with(DayOfWeek.TUESDAY)
                .withHour(1).withMinute(0).withSecond(0).withNano(0);
        
        if (now.isAfter(thisWeekTuesday)) {
            // 如果当前时间已经过了本周二凌晨1点，那么应该在本周二清理
            result = thisWeekTuesday;
        } else {
            // 如果当前时间还没到本周二凌晨1点，那么应该在上周二清理
            result = thisWeekTuesday.minusWeeks(1);
        }
        
        return result;
    }
}
